<?php

namespace app\model;

use app\library\DataReturn;
use Exception;
use think\db\connector\Mysql;
use think\db\exception\DbException;
use think\db\Query;
use think\Model;

/**
 * 模型基类
 */
class BaseModel extends Model
{

    protected $autoWriteTimestamp = true;
    protected $defaultSoftDelete = 0;

    const statusYes = 1; // 启用
    const statusNo = 2; //禁用
    static $statusOptions = [
        self::statusYes => '启用',
        self::statusNo => '禁用'
    ];

    // 数据来源
    const dataSourceFromManual = 1; // 手动
    const dataSourceFromYoPoint = 2; // 友朋


    /**
     * 获取带分页的列表 传统page参数
     * @param $limit
     * @param array $where
     * @param string $order
     * @param string $field
     * @return DataReturn
     */
    public function getPageList($limit, array $where = [], string $field = "*", string $order = "id desc"): DataReturn
    {
        try {
            $list = $this->field($field)->where($where)->order($order)->paginate($limit)->toArray();
            $list = array(
                'total' => $list['total'],
                'rows' => $list['data'],
                'per_page' => $list['per_page'],
                'current_page' => $list['current_page'],
                'last_page' => $list['last_page'],
            );
        } catch (Exception $e) {
            return dataErrorReturn($e->getMessage());
        }

        return dataReturn($list);
    }

    /**
     * 根据数字类型字段进行分页查询（大数据）使用paginateX方法
     * 官方解释:
     * 对于大量数据的分页查询，系统提供了一个高性能的paginateX分页查询方法，用法和paginate分页查询存在一定区别。
     * 如果你要分页查询的数据量在百万级以上，使用paginateX方法会有明显提升，尤其是在分页数较大的情况下。
     * 并且由于针对大数据量而设计，该分页查询只能采用简洁分页模式，所以没有总数。
     * @param $limit
     * @param array $where
     * @param string $field
     * @param string $order
     * @return DataReturn
     */
    public function getNumberFieldPageList($limit, array $where = [], string $field = "*", string $order = "id desc"): DataReturn
    {
        try {
            $list = $this->field($field)->where($where)->order($order)->paginateX($limit, 'id')->toArray();
            $list = array(
                'total' => $list['total'] ?? null,
                'rows' => $list['data'],
                'per_page' => $list['per_page'],
                'current_page' => $list['current_page'],
                'last_page' => $list['last_page'],
            );
            return dataReturn($list);
        } catch (DbException $e) {
            return dataErrorReturn($e->getMessage());
        }
    }

    /**
     * 根据最后ID查询更多N个ID降序数据 使用more方法(id desc)
     * @param $limit
     * @param numeric $lastID 0 标识初始化
     * @param array $where
     * @param string $field
     * @return DataReturn
     */
    public function getMorePageIdDescList($limit, $lastID, array $where = [], string $field = "*"): DataReturn
    {
        try {
            // 计算总数
            $total = $this->where($where)->count('id');
            // 根据ID获取更多
            $lastID > 0 && $where[] = ['id', '<', $lastID];
            $list = $this->field($field)
                ->where($where)
                ->order('id desc')->limit($limit)->select()->toArray();
            if (!empty($list)) {
                $lastKey = array_key_last($list);
                $nextLastID = $list[$lastKey]['id'];
            }else{
                $nextLastID = $lastID;
            }
            $list = array(
                'total' => $total,
                'rows' => $list,
                'last_id' => $nextLastID,
                'limit' => (int)$limit,
            );

            return dataReturn($list);
        } catch (Exception $e) {
            return dataErrorReturn($e->getMessage());
        }
    }

    /**
     * 根据最后ID查询更多N个按照order排序数据
     * @param $limit
     * @param $lastID
     * @param array $where
     * @param mixed $order
     * @param string $field
     * @return DataReturn
     */
    public function getMorePageListByOrder($limit, $lastID, array $where = [], $order='id desc', string $field = "*"): DataReturn
    {
        try {
            // 计算总数
            $total = $this->where($where)->count('id');
            // 根据ID获取更多
            $lastID > 0 && $where[] = ['id', '<', $lastID];
            $list = $this->field($field)
                ->where($where)
                ->order($order)->limit($limit)->select()->toArray();
            if (!empty($list)) {
                $lastKey = array_key_last($list);
                $nextLastID = $list[$lastKey]['id'];
            }else{
                $nextLastID = $lastID;
            }
            $list = array(
                'total' => $total,
                'rows' => $list,
                'last_id' => $nextLastID,
                'limit' => (int)$limit,
            );

            return dataReturn($list);
        } catch (Exception $e) {
            return dataErrorReturn($e->getMessage());
        }
    }


    /**
     * 获取所有的数据不分页
     * @param array $where
     * @param string $order
     * @param string $field
     * @return DataReturn
     */
    public function getAllList(array $where = [], string $field = "*", string $order = "id desc"): DataReturn
    {
        try {

            $list = $this->field($field)->where($where)->order($order)->select();
        } catch (Exception $e) {
            return dataErrorReturn($e->getMessage());
        }

        return dataReturn($list);
    }

    /**
     * 获取指定条目的数据
     * @param array $where
     * @param int $limit
     * @param string $field
     * @param string $order
     * @return DataReturn
     */
    public function getLimitList(array $where = [], int $limit = 10, string $field = "*", string $order = "id desc"): DataReturn
    {
        try {
            $list = $this->field($field)->where($where)->order($order)->limit($limit)->select();
        } catch (Exception $e) {
            return dataErrorReturn($e->getMessage());
        }

        return dataReturn($list);
    }

    /**
     * 根据id获取信息
     * @param $id
     * @param string $pk
     * @param string $field
     * @return DataReturn
     */
    public function getInfoById($id, string $pk = 'id', string $field = '*'): DataReturn
    {
        try {

            $info = $this->field($field)->where($pk, $id)->find();
        } catch (Exception $e) {
            return dataErrorReturn($e->getMessage());
        }

        return dataReturn($info);
    }

    /**
     * 根据ids获取信息
     * @param $ids
     * @param string $pk
     * @param string $field
     * @return DataReturn
     */
    public function getInfoByIds($ids, string $pk = 'id', string $field = '*'): DataReturn
    {
        try {

            $list = $this->field($field)->whereIn($pk, $ids)->select();
        } catch (Exception $e) {
            return dataReturn($e->getMessage());
        }

        return dataReturn($list);
    }

    /**
     * 根据UUID获取信息
     * @param $uuid
     * @param mixed $field
     * @return DataReturn
     */
    public function getInfoByUUID($uuid, $field = '*'): DataReturn
    {
        try {
            $info = $this->field($field)->where('uuid', $uuid)->find();
        } catch (Exception $e) {
            return dataErrorReturn($e->getMessage());
        }

        return dataReturn($info);
    }

    /**
     * 获取IdName(keyValue)列表
     * @param array $where
     * @param string $field
     * @param string $pk
     * @return DataReturn
     */
    public function getIdNameKeyValueList(array $where = [], string $field = 'name', string $pk = 'id'): DataReturn
    {
        $list = $this->where($where)->order(['id'=>'desc'])->column($field, $pk);
        return dataReturn($list);
    }

    /**
     * 获取IdNameRow({id=>'', name=''})列表
     * @param array $where
     * @param string $field
     * @param string $pk
     * @return DataReturn
     */
    public function getIdNameRowList(array $where = [], string $field = 'name', string $pk = 'id'): DataReturn
    {
        $list = $this->where($where)->column($field, $pk);
        $_list = [];
        foreach ($list as $key => $item) {
            $_list[] = array(
                $pk => $key,
                $field => $item
            );
        }
        return dataReturn($_list);
    }

    /**
     * 获取字段最大值
     * @param array $where
     * @param string $field
     * @return int|mixed|Query
     */
    public function getMax(array $where = [], string $field = 'sort'){
        $max = $this->where($where)->max($field);
        return !empty($max) ? $max : 1;
    }

    /**
     * 根据id获取信息
     * @param array $where
     * @param string $field
     * @return DataReturn
     */
    public function findOne(array $where, string $field = '*'): DataReturn
    {
        try {

            $info = $this->field($field)->where($where)->find();
        } catch (Exception $e) {
            return dataErrorReturn($e->getMessage());
        }

        return dataReturn($info);
    }

    /**
     * 添加单条数据
     * @param $param
     * @return DataReturn
     */
    public function insertOne($param): DataReturn
    {
        try {
            if (empty($param['create_time'])) {
                $param['create_time'] = time();
            }
            $id = $this->insertGetId($param);
        } catch (Exception $e) {
            return dataErrorReturn($e->getMessage());
        }

        return dataReturn(['id' => $id], '添加成功');
    }

    /**
     * 批量添加
     * @param array $param
     * @return DataReturn
     */
    public function insertBatch(array $param): DataReturn
    {
        try {
            foreach ($param as &$item) {
                if (empty($item['create_time'])) {
                    $item['create_time'] = time();
                }
            }
            $this->insertAll($param);

        } catch (Exception $e) {
            return dataErrorReturn($e->getMessage());
        }

        return dataReturn([], '添加成功');
    }

    /**
     * 根据id更新数据
     * @param $param
     * @param $id
     * @param string $pk
     * @return DataReturn
     */
    public function updateById($param, $id, string $pk = 'id'): DataReturn
    {
        try {
            if (empty($param['update_time'])) {
                $param['update_time'] = time();
            }
            $this->where($pk, $id)->update($param);

        } catch (Exception $e) {
            return dataErrorReturn($e->getMessage());
        }

        return dataReturn([], '更新成功');
    }

    /**
     * 根据where条件更新数据
     * @param $param
     * @param $where
     * @return DataReturn
     */
    public function updateByWehere($param, $where): DataReturn
    {
        try {
            if (empty($param['update_time'])) {
                $param['update_time'] = time();
            }
            $this->where($where)->update($param);
        } catch (Exception $e) {
            return dataErrorReturn($e->getMessage());
        }

        return dataReturn([], '更新成功');
    }

    /**
     * 根据ids更新
     * @param $param
     * @param $ids
     * @param string $pk
     * @return DataReturn
     */
    public function updateByIds($param, $ids, string $pk = 'id'): DataReturn
    {
        try {
            if (empty($param['update_time'])) {
                $param['update_time'] = time();
            }
            $this->whereIn($pk, $ids)->update($param);
        } catch (Exception $e) {
            return dataErrorReturn($e->getMessage());
        }

        return dataReturn([], '更新成功');
    }

    /**
     * 根据id删除
     * @param $id
     * @param bool $force false 软删除; true 物理删除
     * @param string $pk
     * @return DataReturn
     */
    public function delById($id, bool $force = false, string $pk = 'id'): DataReturn
    {
        try {
            //$this->where($pk, $id)->force($force)->delete();
            $dataObject = $this->find([$pk => $id]);
            if (empty($dataObject)) {
                makeException("删除失败[原始数据不存在], 模型[" . $this->getName() . "], ID:$id");
            }
            $dataObject->force($force)->delete();
        } catch (Exception $e) {
            return dataErrorReturn($e->getMessage());
        }

        return dataReturn([], '删除成功');
    }

    /**
     * 根据$where条件删除
     * @param bool $force false 软删除; true 物理删除
     * @param $where
     * @return DataReturn
     */
    public function delByWhere($where, bool $force = false): DataReturn
    {
        try {
            $idList = $this->where($where)
                ->column($this->getPk());
            if (empty($idList)) {
                $lastSql = $this->getLastSql();
                makeException("条件删除失败[未找到复合条件的数据], 模型[" . $this->getName() . "], SQL:$lastSql");
            }
            foreach ($idList as $id) {
                $this->delById($id, $force, $this->getPk());
            }
        } catch (Exception $e) {
            return dataErrorReturn($e->getMessage());
        }

        return dataReturn([], '删除成功');
    }

    /**
     * 根据ids删除
     * @param array $ids
     * @param bool $force false 软删除; true 物理删除
     * @param string $pk
     * @return DataReturn
     */
    public function delByIds(array $ids, bool $force = false, string $pk = 'id'): DataReturn
    {
        try {
//            $this->whereIn($pk, $ids)->force($force)->delete();
            foreach ($ids as $id) {
                $this->delById($id, $force, $pk);
            }
        } catch (Exception $e) {
            return dataErrorReturn($e->getMessage());
        }

        return dataReturn([], '删除成功');
    }

    /**
     * 检测数据唯一
     * @param $where
     * @param int $id
     * @param string $pk
     * @return DataReturn
     */
    public function checkUnique($where, int $id = 0, string $pk = 'id'): DataReturn
    {
        try {

            if (empty($id) || $id <= 0) {
                $has = $this->field($pk)->where($where)->find();
            } else {
                $has = $this->field($pk)->where($where)->where($pk, '<>', $id)->find();
            }
        } catch (Exception $e) {
            return dataErrorReturn($e->getMessage());
        }

        return dataReturn(['is_has' => !empty($has)], '获取成功');
    }

    /**
     * 增加数据
     * @param $where
     * @param $field
     * @param $num
     * @return DataReturn
     */
    public function incData($where, $field, $num): DataReturn
    {
        try {
            $this->where($where)->inc($field, $num)->update();
        } catch (Exception $e) {
            return dataErrorReturn($e->getMessage());
        }

        return dataReturn([], '操作成功');
    }

    /**
     * 减少数据
     * @param $where
     * @param $field
     * @param $num
     * @return DataReturn
     */
    public function decData($where, $field, $num): DataReturn
    {
        try {

            $this->where($where)->dec($field, $num)->update();
        } catch (Exception $e) {
            return dataErrorReturn($e->getMessage());
        }

        return dataReturn([], '操作成功');
    }

    /**
     * 获取模型所有字段信息
     * @return DataReturn
     */
    public function showFullFields(): DataReturn
    {
        static $allFieldsInfo = [];
        if (empty($allFieldsInfo)) {
            /**
             * @var Mysql $db
             */
            $db = $this->db();
            //$allFieldsInfo = $db->getTableFields($this->table); // 所有字段名(只是字段名)的数组
            $allFieldsInfo = $db->getFields($this->table);
        }
        return dataReturn($allFieldsInfo);
    }

}